#include 	"ipmsg.h"
#include 	"MyIpmsg.h"

#define		PUSH(p) 	{((p)->pre) = tail; tail->next = (p); tail = tail->next;}
#define		POP(tail)	{p = (tail); (tail) = (tail)->pre; if ((tail) != NULL) (tail)->next = NULL; free(p);}

typedef struct stack
{
	DIR		*dp;
	time_t		ctime;
	time_t		mtime;
	struct stack	*next;
	struct stack	*pre;
}stack;

/*---------------------------发送文件线程的回调函数-------------------------------------*/
void * sendfiles(void * arg)
{
	int 		sockfdTCP;
	int		sockfd;
	int 		userid;
	ipmsg_user_list * p = NULL;
	char 		UDPsendbuf[MAX_SEND_FILE_HEADER_LEN] = {'\0'};
	char 		UDPsendtemp[MAXSOCKBUF] = {'\0'};
	char		TCPsendbuf[1449] = {'\0'};
	char		TCPtemp[1449] = {'\0'};
	char		* t = NULL, * tt = NULL;
	sendfilearg 	* args = (sendfilearg * ) arg;
	int 		i;
	struct stat 	filestruct;
	ipmsgdata 	data;
	struct in_addr 	addr_temp;
	time_t		time1,time2;
	FILE		* fp = NULL;
	ssize_t		numbytes;
	struct sockaddr cliaddr;
	socklen_t	addrlen;
	int		sendfilenum = args->filenum;
	int		malloc_flag = 0;
	char		filename_temp[PATH_MAX + 1];
	
	/*设置本线程的状态为接收到cancel信号后取消本线程*/
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

	memset(UDPsendbuf, 0, MAXSOCKBUF);
	memset( & data, 0, sizeof(data));
	if (args->flags == 1) {
		userid = atoi(args->to);
		p = search_user( & userid, NULL, NULL);
	}
	
	if (args->flags == 3) {
		if (inet_aton (args->to, & addr_temp) == 0) {
			perror("inet_aton error");
			return NULL;
		}
		
		p = search_user(NULL, & addr_temp, NULL);
		
		if (!p) {
			p = (ipmsg_user_list * )malloc(sizeof(ipmsg_user_list));
			malloc_flag = 1;
			bzero( &(p->user_addr), sizeof(p->user_addr));
			p->user_addr.sin_family = AF_INET;
			memcpy( & p->user_addr.sin_addr, & addr_temp, sizeof(addr_temp));
			p->user_addr.sin_port = htons(DEFAULTPORT);
		}
	}
	
	if(args->flags == 4)
		p = search_user(NULL, NULL, args->to);
	
	if (!p) {
		printf("There is not this user!\n");
		return NULL;
	}
	
	if (args->flags == 2) {	/*向所有人发送时*/
	
	}
	
	for (i = 0; i < args->filenum - 1; i++) {
		if (stat(args->filename[i], & filestruct) == -1) {
			perror("stat error");
			return NULL;
		}
		
		t = strchr(args->filename[i], ':');
		while (t) {
			memmove(t + 1, t, strlen(t) + 1);
			* t = ':';
			t = strchr(t + 2, ':');
		}
		strncpy(filename_temp, args->filename[i], PATH_MAX + 1);
		t = strrchr(filename_temp, '/');
		if (t && (*(t + 1) == '\0')) {
			*t = '\0';
			t = strrchr(filename_temp, '/');
			memmove(filename_temp, t + 1, strlen(t + 1) + 1);
		}
		else if (t && ( *(t + 1) != '\0'))
			memmove(filename_temp, t + 1, strlen(t + 1) + 1);
		sprintf(UDPsendtemp, "%x:%s:%lx:%lx:%lu:\a", (unsigned int)i, \
				filename_temp, filestruct.st_size, filestruct.st_mtime, args->fileattr[i]);
		
		strcat(UDPsendbuf,UDPsendtemp);
	}
	
	t = strchr(args->filename[i], ':');
	while (t) {
		memmove(t + 1, t, strlen(t) + 1);
		* t = ':';
		t = strchr(t + 2, ':');
	}
	if (stat(args->filename[i], & filestruct) == -1) {
		perror("stat error");
		printf("%s\n", args->filename[i]);
		return NULL;
	}
	
	strncpy(filename_temp, args->filename[i], PATH_MAX + 1);
	t = strrchr(filename_temp, '/');
	if (t && (*(t + 1) == '\0')) {
		*t = '\0';
		t = strrchr(filename_temp, '/');
		memmove(filename_temp, t + 1, strlen(t + 1) + 1);
	}
	else if (t && ( *(t + 1) != '\0'))
		memmove(filename_temp, t + 1, strlen(t + 1) + 1);
	
	sprintf(UDPsendtemp, "%x:%s:%04lx:%lx:%lu:", \
			(unsigned int)i, filename_temp, filestruct.st_size, filestruct.st_mtime, args->fileattr[i]);
	
	strcat(UDPsendbuf, UDPsendtemp);
	strncpy(data.sendfileheader, UDPsendbuf, strlen(UDPsendbuf) + 1);
	ipmsgsendbcast( & (p->user_addr), IPMSG_SENDMSG | IPMSG_FILEATTACHOPT | IPMSG_SENDCHECKOPT, & data);

	i = 0;
	arrivetimeflag = 1;
#if 1	
	while (1) {		/*超时重发*/
		if (repeatflag && arrivetimeflag) {
			ipmsgsendbcast( & (p->user_addr), \
					IPMSG_SENDMSG | IPMSG_FILEATTACHOPT | IPMSG_SENDCHECKOPT, & data);
			
			time1 = time(NULL);
			repeatflag = 0;
			i++;
		}
		time2 = time(NULL);
		
		if ( (time2 - time1) < MAXREPEATTIME && !recvflag) {
			arrivetimeflag = 0;
			continue;
		}
		else
			arrivetimeflag = 1;
		
		if (recvflag)
			break;
		
		if (i > 5) {
			printf("send failed!\n");
			return NULL;
		}
	}
#endif
#if 1	
	if ( (sockfdTCP = socket(AF_INET, SOCK_STREAM, 0)) < 0) {	/*建立TCP监听*/
		perror("socket error");
		return NULL;
	}
	if (bind(sockfdTCP, (struct sockaddr * ) &me, sizeof(me)) == -1) {
		perror("bind error");
		close(sockfdTCP);
		return NULL;
	}
	
	if (listen(sockfdTCP, 1) == -1) {
		perror("listen error");
		close(sockfdTCP);
		return NULL;
	}
	
	while (1) {
		addrlen = sizeof(cliaddr);
		if ((sockfd = accept(sockfdTCP, &cliaddr, &addrlen)) == -1) {
			perror("accept error");
			close(sockfdTCP);
			return NULL;
		}
		
		memset(TCPtemp, 0, 1449);
		

		if (args->fileattr[FileID] == IPMSG_FILE_REGULAR) {	/*传送的是文件*/
			i = 0;
			while (1) {
				memset(TCPsendbuf, 0, 1449);
				if ( (numbytes = recv(sockfd, TCPsendbuf, 1448, 0)) == -1) {
					perror("recv error");
					close(sockfdTCP);
					return NULL;
				}
				strcat(TCPtemp, TCPsendbuf);
				t = strchr(TCPtemp, ':');
				i = 1;
				while (t) {
					tt = t;
					t = strchr(t + 1, ':');
					i++;
				}
				if (i == 9) {
					if ( *(tt + 1) == '\0') {
						break;
					}
				}
			}
			ipmsgswitch( & data, TCPtemp);	
			printf("file\n");
			if (recvflag) {	/*收到返回信息，开始发送文件*/
				if (startsendflag == 1) {
					if (FileID > args->filenum - 1 || FileID < 0) {
						printf("There is no this file\n");
						startsendflag = 0;
						close(sockfdTCP);
						return NULL;
					}
					if ( (fp = fopen(args->filename[FileID], "r")) == NULL) {
						perror("fopen");
						close(sockfdTCP);
						return NULL;
					}
					while (1) {
						if ( (numbytes = fread(TCPsendbuf, sizeof(char), 1448, fp)) < 1448) {
							if (ferror(fp)) {
								perror("fread");
								close(sockfdTCP);
								fclose(fp);
								return NULL;
							}
						}
						if (send(sockfd, TCPsendbuf, numbytes, 0) == -1) {
							perror("send");
							fclose(fp);
							close(sockfdTCP);
							return NULL;
						}
						if (feof(fp))
							break;
					}
					startsendflag = 0;
					fclose(fp);
				}
			}
		}
		else {			/*传送的是文件夹*/
			i = 0;
			while (1) {
				memset(TCPsendbuf, 0, 1449);
				if ( (numbytes = recv(sockfd, TCPsendbuf, 1448, 0)) == -1) {
					perror("recv error");
					close(sockfdTCP);
					return NULL;
				}
				strcat(TCPtemp, TCPsendbuf);
				t = strchr(TCPtemp, ':');
				i = 1;
				while (t) {
					tt = t;
					t = strchr(t + 1, ':');
					i++;
				}
				if (i == 8) {
					if ( *(tt + 1) == '\0') {
						break;
					}
				}
			}
			ipmsgswitch( & data, TCPtemp);	
			if (recvflag) {
				if (startsendflag) {
					if (FileID > args->filenum -1 || FileID < 0) {
						printf("There is no this directory\n");
						startsendflag = 0;
						close(sockfdTCP);
						return NULL;
					}
					if(senddir(args->filename[FileID], sockfd) == 0) {
						close(sockfdTCP);
						startsendflag = 0;
						return NULL;
					}
					close(sockfdTCP);
					startsendflag = 0;
				}
			}
		}
		sendfilenum--;
		if(sendfilenum == 0)
			break;
	}
	printf("translate finished\n(ipmsg)");
	close(sockfdTCP);
	if (malloc_flag) free(p);
	free(args);
#endif
	return NULL;
}

int senddir(char dir[], int socksendfd)
{
	struct dirent	nextdp;
	struct dirent	*q = NULL;
	int 		re;
	stack		*head = NULL;
	stack		*tail = NULL;
	stack		*p = NULL;
	char		path[PATH_MAX + 1] = {'\0'};
	struct stat	buf;
	char		*pp = NULL;
	char		*t = NULL;
	int		depth = 0;
	char		TCPsendbuf[65536] = {'\0'};
	char		TCPsend[1449] = {'\0'};
	char		temp[5] = {'\0'};
	FILE		*fp = NULL;
	int		numbytes;
	char		filename_temp[PATH_MAX + 1];
	
	head = (stack *)malloc(sizeof(stack));
	tail = head;
	head->next = NULL;
	head->pre = NULL;
	head->dp = opendir(dir);
	depth++;
	strncpy(path, dir, PATH_MAX + 1);
	if (lstat(path, &buf) < 0) {
		perror("lstat error");
		return 0;
	}
	
	strncpy(filename_temp, dir, PATH_MAX + 1);
	t = strrchr(filename_temp, '/');
	if (t && (*(t + 1) == '\0')) {
		*t = '\0';
		t = strrchr(filename_temp, '/');
		memmove(filename_temp, t + 1, strlen(t + 1) + 1);
	}
	else if (t && ( *(t + 1) != '\0'))
		memmove(filename_temp, t + 1, strlen(t + 1) + 1);
	
	pp = strchr(filename_temp, ':');
	if (pp != NULL) {
		strncpy(&TCPsendbuf[4], filename_temp, pp - filename_temp);
		TCPsendbuf[4 + strlen(&TCPsendbuf[4])] = ':';
		strncpy(&TCPsendbuf[4 + strlen(&TCPsendbuf[4]) + 1], pp + 1, strlen(pp + 1) +1);
		snprintf(&TCPsendbuf[4 + strlen(&TCPsendbuf[4])], 65535, ":%09lx:%lx:%lx=%lx:%lx=%lx:", \
				0UL, IPMSG_FILE_DIR, IPMSG_FILE_MTIME, buf.st_mtime, IPMSG_FILE_CREATETIME, buf.st_ctime);
	}
	else {
		snprintf(&TCPsendbuf[4], 65535, ":%s:%09lx:%lx:%lx=%lx:%lx=%lx:", filename_temp, \
				0UL, IPMSG_FILE_DIR, IPMSG_FILE_MTIME, buf.st_mtime, IPMSG_FILE_CREATETIME, buf.st_ctime);
	}
	
	head->ctime = buf.st_ctime;
	head->mtime = buf.st_mtime;
	snprintf(temp, 5, "%04x", strlen(&TCPsendbuf[4]) + 4);
	strncpy(TCPsendbuf, temp, 4);
	pp = strrchr(path, '/');
	if ( pp && *(pp + 1) != '\0') {
		path[strlen(path) + 1] = '\0';
		path[strlen(path)] = '/';
	}
	if (!pp) {
		path[strlen(path) + 1] = '\0';
		path[strlen(path)] = '/';
	}
	
	if (send(socksendfd, TCPsendbuf, strlen(TCPsendbuf), 0) == -1) {
		perror("send error1");
		return 0;
	}
	memset(TCPsendbuf, 0, strlen(TCPsendbuf));
	
	while (1) {
		re = readdir_r(tail->dp, &nextdp, &q);
		if (re) {
			perror("readdir_r error");
			break;
		}
		
		if (q == NULL) {
			snprintf(&TCPsendbuf[4], 65535, ":%s:%x:%lx:%lx=%lx:%lx=%lx:", ".", 0, \
					IPMSG_FILE_RETPARENT, IPMSG_FILE_MTIME, \
					tail->mtime, IPMSG_FILE_CREATETIME, tail->ctime);
			snprintf(temp, 5, "%04x", strlen(&TCPsendbuf[4]) + 4);
			strncpy(TCPsendbuf, temp, 4);
			if (send(socksendfd, TCPsendbuf, strlen(TCPsendbuf), 0) == -1) {
				perror("send error2");
				return 0;
			}
			memset(TCPsendbuf, 0, strlen(TCPsendbuf));
			
			pp = strrchr(path, '/');
			if (pp == NULL) {
				closedir(tail->dp);
				break;
			}
			if ( *(pp + 1) == '\0') {
				*pp = '\0';
				pp = strrchr(path, '/');
			}
			if (pp != NULL)
				*(pp + 1) = '\0';
			closedir(tail->dp);
			POP(tail);
			depth--;
			if (depth == 0) break;
			else continue;
		}
		
		if (strcmp(nextdp.d_name, ".") && strcmp(nextdp.d_name, "..")) {
			strncat(path, nextdp.d_name, strlen(nextdp.d_name) + 1);
			printf("%s\n", path);
			if (lstat(path, &buf) < 0) {
				perror("lstat");
			}
			if (S_ISDIR(buf.st_mode)) {
				pp = strchr(nextdp.d_name, ':');
				if (pp != NULL) {
					strncpy(&TCPsendbuf[4], nextdp.d_name, pp - path);
					TCPsendbuf[4 + strlen(&TCPsendbuf[4])] = ':';
					strncpy(&TCPsendbuf[4 + strlen(&TCPsendbuf[4]) + 1], pp + 1, strlen(pp + 1) +1);
					snprintf(&TCPsendbuf[4 + strlen(&TCPsendbuf[4])], 65535, \
							":%09lx:%lx:%lx=%lx:%lx=%lx:",0LU, IPMSG_FILE_DIR, \
							IPMSG_FILE_MTIME, buf.st_mtime, \
							IPMSG_FILE_CREATETIME, buf.st_ctime);
				}
				else {
					snprintf(&TCPsendbuf[4], 65535, ":%s:%09lx:%lx:%lx=%lx:%lx=%lx:", \
							nextdp.d_name, 0LU, \
							IPMSG_FILE_DIR, IPMSG_FILE_MTIME, buf.st_mtime, \
							IPMSG_FILE_CREATETIME, buf.st_ctime);
				}
				snprintf(temp, 5, "%04x", strlen(&TCPsendbuf[4]) + 4);
				strncpy(TCPsendbuf, temp, 4);
				if (send(socksendfd, TCPsendbuf, strlen(TCPsendbuf), 0) == -1) {
					perror("send error3");
					return 0;
				}
				memset(TCPsendbuf, 0, strlen(TCPsendbuf));
				
				path[strlen(path) + 1] = '\0';
				path[strlen(path)] = '/';
				p = (stack *)malloc(sizeof(stack));
				p->next = NULL;
				p->pre = NULL;
				p->dp = opendir(path);
				p->ctime = buf.st_ctime;
				p->mtime = buf.st_mtime;
				PUSH(p);
				depth++;
			}
			else {
				pp = strchr(nextdp.d_name, ':');
				if (pp != NULL) {
					strncpy(&TCPsendbuf[4], nextdp.d_name, pp - path);
					TCPsendbuf[4 + strlen(&TCPsendbuf[4])] = ':';
					strncpy(&TCPsendbuf[4 + strlen(&TCPsendbuf[4]) + 1], pp + 1, strlen(pp + 1) +1);
					snprintf(&TCPsendbuf[4 + strlen(&TCPsendbuf[4])], 65535, \
							":%09lx:%lx:%lx=%lx:%lx=%lx",buf.st_size, IPMSG_FILE_REGULAR, \
							IPMSG_FILE_MTIME, buf.st_mtime, IPMSG_FILE_CREATETIME, \
							buf.st_ctime);
				}
				else {
					snprintf(&TCPsendbuf[4], 65535, ":%s:%09lx:%lx:%lx=%lx:%lx=%lx", nextdp.d_name, \
							buf.st_size, IPMSG_FILE_REGULAR, IPMSG_FILE_MTIME, buf.st_mtime, \
							IPMSG_FILE_CREATETIME, buf.st_ctime);
				}
				snprintf(temp, 5, "%04x", strlen(&TCPsendbuf[4]) + 4);
				strncpy(TCPsendbuf, temp, 4);
				if (send(socksendfd, TCPsendbuf, strlen(TCPsendbuf), 0) == -1) {
					perror("send error4");
					return 0;
				}
				memset(TCPsendbuf, 0, strlen(TCPsendbuf));
				if ((fp = fopen(path, "r")) == NULL) {
					perror("fopen error");
					return 0;
				}
				while (1) {
					if ( (numbytes = fread(TCPsend, sizeof(char), 1448, fp)) < 1448) {
						if (ferror(fp)) {
							perror("fread");
							fclose(fp);
							return 0;
						}
					}
					if (send(socksendfd, TCPsend, numbytes, 0) == -1) {
						perror("send error5");
						fclose(fp);
						return 0;
					}
					if (feof(fp))
						break;
				}
				fclose(fp);
				path[strlen(path)] = '\0';
				pp = strrchr(path, '/');
				if ( *(pp + 1) == '\0') {
					*pp = '\0';
					pp = strrchr(path, '/');
				}
				*(pp + 1) = '\0';
			}
		}
	}

	return 1;
}
